import { isUndefined, isPlainObject, extend, isFunction, isString, hasOwn } from '@web-utils/core'
import { bus } from '@web-utils/vue/mixin/bus'

/**
 * 临时缓存
 * @type {{}}
 */
const cache = {}

export default {
  initHooks: [],
  props: {
    id: [String, Number]
  },
  data() {
    return {
      disabled: false,
      isFormSaved: false,
      isFormLoaded: false,
      formLoadingStatus: 0,
      entity: {},
      dictData: {}
    }
  },
  computed: {
    /**
     * 表单是否已启用
     * @returns {boolean}
     */
    isEnabled() {
      return !this.isDisabled
    },
    /**
     * 表单是否已禁用
     * @returns {boolean}
     */
    isDisabled() {
      return this.disabled
    }
  },
  watch: {
    id: {
      immediate: true,
      handler: 'initForm'
    }
  },
  methods: {
    /**
     * 关闭表单
     */
    closeForm() {
      this.$closeTab()
    },
    /**
     * 通知要更新的组件 id
     * @param viewId {string?} 要更新的组件 viewId, 不指定默认获取 options 里的 relativeViewId
     */
    updateRelativeView(viewId) {
      const relativeView = viewId || this.$options.relativeViewId
      this.$refreshHome('WorkToDoList')
      this.$refreshWork()
      if (relativeView) {
        this.$reloadTableView(relativeView, this.entity)
        this.$reloadTreeView(relativeView, this.entity)
      }
    },
    /**
     * 判断 id 是否合法
     * @param id {string?}
     * @returns {boolean}
     */
    validateId(id = this.entity.id) {
      if (isString(id)) {
        return id && id !== '-1'
      }
      return !!id && id > 0
    },
    /**
     * 判断是不是新建
     * @param id {string?}
     * @returns {boolean}
     */
    isNew(id = this.entity.id) {
      return !this.validateId(id)
    },
    /**
     * 清除表单验证结果
     * @returns {Promise<void>}
     */
    async invalidate() {
      await this.$nextTick()
      this.$refs.form?.clearValidate()
    },
    /**
     * 验证表单
     * @returns {Promise<void>}
     */
    async validate() {
      let valid
      if (!this.$refs.form) {
        throw Error('请在表单上添加 ref="form"')
      }
      try {
        valid = await this.$refs.form.validate()
      } catch (e) {
        throw Error('表单验证不通过!')
      }
      if (valid === undefined) {
        throw Error('请在表单上添加 :model="entity"')
      } else {
        return valid
      }
    },
    /**
     * 清除指定表单字段的校验结果
     * @param fields {Array<string>}
     * @returns {Promise<void>}
     */
    async clearValidate(fields) {
      await this.$nextTick()
      this.$refs.form?.clearValidate(fields)
    },
    /**
     * 加载实体
     * @param id {string}
     * @returns {Promise<{}|*>}
     */
    async loadEntity(id) {
      if (isUndefined(id)) {
        return this.entity
      }
      let res

      if (this.isNew(id)) {
        if (isFunction(this.create)) {
          const response = await this.create()
          res = response.data
        } else {
          res = { data: this.entity }
        }
      } else {
        const response = await this.load(id)
        res = response.data
      }

      if (hasOwn(res.data, 'createId') && !res.data.createId) {
        res.data.createId = this.userId
      }

      if (hasOwn(res.data, 'creator') && !res.data.creator) {
        res.data.creator = this.userId
      }

      if (res.data.dictOption) {
        this.dictData = Object.freeze(res.data.dictOption)
        delete res.data.dictOption
      }
      return res.data
    },
    /**
     * 初始化实体
     * @param id {string}
     * @returns {Promise<void>}
     */
    async initEntity(id) {
      this.entity = await this.loadEntity(id)
    },
    /**
     * 初始化表单
     * @param id {string?}
     * @returns {Promise<void>}
     */
    async initForm(id = this.entity.id) {
      id = id || this.id
      try {
        console.log('initForm')

        this.formLoadingStatus = 0
        this.setFormLoaded(false)

        if (this._unwatch) {
          this._unwatch()
          delete this._unwatch
        }

        console.log('initEntity')
        await this.initEntity(id)

        const initHooks = this.$options.initHooks
        if (initHooks.length) {
          for (let i = 0; i < initHooks.length; i++) {
            const method = initHooks[i]
            if (isFunction(this[method])) {
              console.log(method)
              await this[method]()
            }
          }
        }

        console.log('initFormState')
        await this.initFormState()

        this._unwatch = this.$watch(
          'entity',
          () => {
            this.setFormSaved(false)
          },
          { deep: true }
        )
      } catch (e) {
        console.log('initFormError')
        this.formLoadingStatus = -1
        this.setFormSaved(true)
        console.error(e)
      }
      this.setFormLoaded(true)
    },
    async initFormState() {
      await this.$nextTick()
      this.setFormSaved(true)

      await this.invalidate()

      const id = this.entity.id
      if (cache[id]) {
        this.setFormDisabled(false)
        delete cache[id]
      } else {
        this.setFormDisabled(this.validateId(id))
      }

      console.log('afterInitForm')
      await this.afterInitForm()

      this.setFormLoaded(true)
    },
    /**
     * 表单初始化完成后
     */
    async afterInitForm() {},
    /**
     * 等待数据更新完成后标记表单为已保存
     * @param saved
     * @returns {Promise<void>}
     */
    async updateFormSaveStatus(saved) {
      await this.$nextTick()
      this.setFormSaved(saved)
    },
    /**
     * 设置表单保存状态
     * @param saved {boolean}
     */
    setFormSaved(saved) {
      this.isFormSaved = saved
    },
    /**
     * 设置表单禁用状态
     * @param disabled
     */
    setFormDisabled(disabled) {
      this.disabled = disabled
    },
    /**
     * 设置表单加载状态
     * @param loaded
     */
    setFormLoaded(loaded) {
      this.isFormLoaded = loaded
    },
    /**
     * 持久化实体
     * @param options {PersistOption?} 配置
     * @returns {Promise<void>}
     */
    async persist(options) {
      try {
        const settings = {
          entity: this.entity,
          message: '保存成功！',
          disabled: false,
          viewId: this.$options.relativeViewId,
          close: true,
          closeForm: false,
          reloadAfterSave: false,
          reloadAfterUpdate: false,
          cache: true
        }
        if (isPlainObject(options)) {
          extend(settings, options)
        }
        await this.validate()
        if (this.isNew()) {
          // 保存
          const { data: res } = await this.save(settings.entity)
          const entity = res.data
          if (isFunction(settings.afterSave)) {
            await settings.afterSave(entity)
          }
          this.notifyAndUpdateView(settings.message, settings.viewId)
          if (isPlainObject(entity)) {
            if (cache && settings.cache) {
              cache[entity.id] = true
            }
            if (settings.closeForm) {
              this.setFormSaved(true)
              this.closeForm()
            } else if (settings.close) {
              this.setFormSaved(true)
              await this.replaceForm(entity.id)
            } else if (settings.reloadAfterSave) {
              await this.initForm(entity.id)
            } else {
              this.entity = entity
              await this.updateFormSaveStatus(true)
            }
          }
        } else {
          // 更新
          const { data: res } = await this.update(settings.entity)
          const entity = res.data
          this.notifyAndUpdateView(settings.message, settings.viewId)
          if (settings.closeForm) {
            this.setFormSaved(true)
            this.closeForm()
          } else if (settings.reloadAfterUpdate) {
            await this.initForm(this.entity.id)
          } else {
            this.entity = isPlainObject(entity) ? entity : this.entity
            await this.updateFormSaveStatus(true)
          }
        }
        this.setFormDisabled(settings.disabled)
      } catch (e) {
        console.error(e)
      }
    },
    /**
     * 新建情况下保存后关闭当前标签并打开新标签
     * @param id {string} 实体 id
     * @param tabTitle {string} 标签名程
     * @param query {Record<string,any>} 路径参数
     */
    async replaceForm(id, tabTitle = '', query = {}) {
      const { path: currentPath, meta } = this.$route
      let path = currentPath
      const title = tabTitle || meta.title
      const pathQuery = query || {}

      if (Object.keys(this.$route.params).length) {
        path = this.$route.matched[this.$route.matched.length - 1].path
        const params = { ...this.$route.params, id }
        for (const key in params) {
          path = path.replace(`:${key}`, params[key])
        }
      }

      let replace = false
      if (path !== currentPath) {
        bus.$emit('closeTab', currentPath, this)
      } else {
        replace = true
      }
      const route = { path, query: { tabTitle: title, ...pathQuery } }
      if (replace) {
        await this.$router.replace(route)
      } else {
        await this.$router.push(route)
      }
    },
    /**
     * 显示保存成功消息并通知 view 更新
     * @param message 提示信息
     * @param viewId {string?} 要更新的组件 viewId, 不指定默认获取 options 里的 relativeViewId
     */
    notifyAndUpdateView(message, viewId) {
      const msg = message || '保存成功！'
      this.$message.success(msg)
      this.updateRelativeView(viewId)
    }
  }
}
